package com.wans.guli.ware.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wans.guli.common.utils.R;
import com.wans.guli.ware.constant.em.PurchaseDetailStatusEnum;
import com.wans.guli.ware.constant.em.PurchaseReceiveStatusEnum;
import com.wans.guli.ware.entity.PurchaseDetailEntity;
import com.wans.guli.ware.entity.WareSkuEntity;
import com.wans.guli.ware.feign.ProductFeignClient;
import com.wans.guli.ware.feign.vo.ProductSkuInfoRespVO;
import com.wans.guli.ware.feign.vo.ProductSkuInfoRestVO;
import com.wans.guli.ware.service.PurchaseDetailService;
import com.wans.guli.ware.vo.PurchaseDoneRestVO;
import com.wans.guli.ware.vo.PurchaseMergeRestVO;
import com.wans.guli.ware.vo.PurchaseUnreceiveRespVO;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wans.guli.common.utils.PageUtils;
import com.wans.guli.common.utils.Query;

import com.wans.guli.ware.dao.PurchaseDao;
import com.wans.guli.ware.entity.PurchaseEntity;
import com.wans.guli.ware.service.PurchaseService;
import org.springframework.transaction.annotation.Transactional;


@Service("purchaseService")
public class PurchaseServiceImpl extends ServiceImpl<PurchaseDao, PurchaseEntity> implements PurchaseService {

    private final PurchaseDetailServiceImpl purchaseDetailService;
    private final ProductFeignClient productFeignClient;
    private final ObjectMapper jacksonObjectMapper;
    private final WareSkuServiceImpl wareSkuService;

    public PurchaseServiceImpl(PurchaseDetailServiceImpl purchaseDetailService, ProductFeignClient productFeignClient, ObjectMapper jacksonObjectMapper, WareSkuServiceImpl wareSkuService) {
        this.purchaseDetailService = purchaseDetailService;
        this.productFeignClient = productFeignClient;
        this.jacksonObjectMapper = jacksonObjectMapper;
        this.wareSkuService = wareSkuService;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils listUnreceive() {
        // 构建默认分页
        HashMap<String, Object> params = new HashMap<>();

        // TODO 用户权限分配
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>().lambda()
                        .eq(PurchaseEntity::getStatus, PurchaseReceiveStatusEnum.CREATED.getStatus())
                        .or()
                        .eq(PurchaseEntity::getStatus, PurchaseReceiveStatusEnum.ASSIGNED.getStatus())
        );

        if (page.getRecords() == null || page.getRecords().isEmpty()) return new PageUtils(page);

        List<PurchaseUnreceiveRespVO> purchaseUnreceiveRespVOS = BeanUtil.copyToList(page.getRecords(), PurchaseUnreceiveRespVO.class);
        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(purchaseUnreceiveRespVOS);

        return pageUtils;
    }

    /**
     * 合并采购需求
     *
     * @param mergeVO 参数 采购单id 需求单ids
     */
    @Override
    @Transactional
    public void mergePurchaseItems(PurchaseMergeRestVO mergeVO) {
        Long purchaseId = mergeVO.getPurchaseId();
        if (purchaseId == null) {
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(PurchaseReceiveStatusEnum.CREATED.getStatus());
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        } else {
            PurchaseEntity purchaseEntity = this.getById(purchaseId);
            if (purchaseEntity == null)
                // 采购单不存在
                throw new RuntimeException("采购单不存在");
            if (!Objects.equals(PurchaseReceiveStatusEnum.CREATED.getStatus(), purchaseEntity.getStatus()))
                // 不是创建状态
                throw new RuntimeException("采购单状态错误");
        }

        // 无法传入 lambda 先转字符串
        String stringPurchaseId = String.valueOf(purchaseId);
        // 进行合并
        List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDetailService.lambdaQuery().in(PurchaseDetailEntity::getId, mergeVO.getItems()).list();
        if (purchaseDetailEntities == null || purchaseDetailEntities.isEmpty())
            throw new RuntimeException("参数错误");
        purchaseDetailEntities.forEach(purchaseDetailEntity -> {
            if (!Objects.equals(PurchaseDetailStatusEnum.CREATED.getStatus(), purchaseDetailEntity.getStatus()))
                // 需求单状态错误 需求不是新建状态
                throw new RuntimeException("需求单状态错误");
            purchaseDetailEntity.setPurchaseId(Long.valueOf(stringPurchaseId));
            purchaseDetailEntity.setStatus(PurchaseReceiveStatusEnum.ASSIGNED.getStatus());
        });

        // TODO 校验这些需求id是否都是创建状态
        boolean updatedBatchById = purchaseDetailService.updateBatchById(purchaseDetailEntities);
        if (!updatedBatchById)
            throw new RuntimeException("合并失败");
    }

    /**
     * 领取采购单
     *
     * @param ids 采购单ids
     */
    @Override
    @Transactional
    public void received(List<Long> ids) {
        if (ids == null || ids.isEmpty()) throw new RuntimeException("参数错误");
        // TODO 性能问题先不管
        List<PurchaseEntity> purchaseEntities = ids.stream().map(id -> {
            PurchaseEntity purchaseEntity = this.getById(id);
            if (purchaseEntity == null)
                // 采购单不存在
                throw new RuntimeException("采购单不存在");
            if (!Objects.equals(PurchaseReceiveStatusEnum.ASSIGNED.getStatus(), purchaseEntity.getStatus()))
                // 不是已分配 状态
                throw new RuntimeException("采购单状态错误");
            purchaseEntity.setStatus(PurchaseReceiveStatusEnum.RECEIVE.getStatus());
            return purchaseEntity;
        }).collect(Collectors.toList());
        if (purchaseEntities.isEmpty()) throw new RuntimeException("参数错误");

        // 获取所有需求与采购单关联的需求
        List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDetailService
                .lambdaQuery().in(PurchaseDetailEntity::getPurchaseId, ids).list();
        // 没有与它关联的需求
        if (purchaseDetailEntities.isEmpty()) throw new RuntimeException("参数错误");
        purchaseDetailEntities.forEach(item -> {
            if (!Objects.equals(item.getStatus(), PurchaseDetailStatusEnum.ASSIGNED.getStatus()))
                // 需求单状态错误 不是已分配状态
                throw new RuntimeException("采购单状态错误");
            item.setStatus(PurchaseDetailStatusEnum.ACTIVE.getStatus());
        });
        boolean updatedBatchPurchaseDetailById = purchaseDetailService.updateBatchById(purchaseDetailEntities);
        if (!updatedBatchPurchaseDetailById)
            throw new RuntimeException("领取失败");

        boolean updatedBatchById = this.updateBatchById(purchaseEntities);
        if (!updatedBatchById)
            throw new RuntimeException("领取失败");
    }

    /**
     * 完成采购单
     *
     * @param purchaseDoneRestVO 采购单ids
     */
    @Override
    public void done(PurchaseDoneRestVO purchaseDoneRestVO) {
        if (purchaseDoneRestVO.getId() == null) throw new RuntimeException("参数错误");
        // TODO 性能问题先不管
        PurchaseEntity purchaseEntity = this.getById(purchaseDoneRestVO.getId());
        if (purchaseEntity == null)
            // 采购单不存在
            throw new RuntimeException("采购单不存在");
        if (
                !Objects.equals(PurchaseReceiveStatusEnum.RECEIVE.getStatus(), purchaseEntity.getStatus()))
            // 不是已领取状态
            throw new RuntimeException("采购单状态错误");
        purchaseEntity.setStatus(PurchaseReceiveStatusEnum.FINISH.getStatus());

        // 获取所有需求与采购单关联的需求
        List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDoneRestVO.getItems().stream().map(item -> {
            PurchaseDetailEntity purchaseDetailEntity = purchaseDetailService.getById(item.getItemId());
            // 需求不存在
            if (purchaseDetailEntity == null) throw new RuntimeException("需求不存在");
            // 是不是该采购单的需求
            if (!Objects.equals(purchaseDetailEntity.getPurchaseId(), purchaseEntity.getId()))
                throw new RuntimeException("参数错误");
            if (!Objects.equals(PurchaseDetailStatusEnum.ACTIVE.getStatus(), purchaseDetailEntity.getStatus()))
                // 状态错误 - 不是正在采购状态
                throw new RuntimeException("采购单状态错误");
            purchaseDetailEntity.setStatus(item.getStatus().intValue());
            // TODO 失败说明 - 数据库并没有该字段
            String reason = item.getReason();
            return purchaseDetailEntity;
        }).collect(Collectors.toList());
        // 没有与它关联的需求
        if (purchaseDetailEntities.isEmpty()) throw new RuntimeException("参数错误");

        // 添加库存
        List<ProductSkuInfoRestVO> productSkuInfoRestVOS = purchaseDetailEntities.stream().map(item -> {
            ProductSkuInfoRestVO productSkuInfoRestVO = new ProductSkuInfoRestVO();
            productSkuInfoRestVO.setSkuId(item.getSkuId());
            productSkuInfoRestVO.setStock(item.getSkuNum());
            productSkuInfoRestVO.setWareId(item.getWareId());
            return productSkuInfoRestVO;
        }).collect(Collectors.toList());

        R skuInfo = productFeignClient.getSkuInfo(productSkuInfoRestVOS);
        if (skuInfo.getCode() != 0)
            throw new RuntimeException("查找商品失败");
        try {
            TypeReference<List<ProductSkuInfoRespVO>> typeReference = new TypeReference<List<ProductSkuInfoRespVO>>() {
            };
            List<ProductSkuInfoRespVO> productSkuInfoRespVOS = jacksonObjectMapper
                    .readValue(
                            jacksonObjectMapper.writeValueAsString(skuInfo.get("data")),
                            typeReference
                    );

            productSkuInfoRespVOS.forEach(item -> {
                // TODO 需要一个锁

                WareSkuEntity wareSkuEntity = wareSkuService.lambdaQuery().eq(WareSkuEntity::getSkuId, item.getSkuId()).one();
                if (wareSkuEntity == null) {
                    // 没有该商品库存信息
                    wareSkuEntity = new WareSkuEntity();
                    BeanUtil.copyProperties(item, wareSkuEntity);
                    wareSkuEntity.setStockLocked(0);
                    boolean save = wareSkuService.save(wareSkuEntity);
                    if (!save) throw new RuntimeException("库存信息保存失败");
                } else {
                    // 存在 更新
                    // 版本先变化
                    Long version = wareSkuEntity.getVersion() + 1;
                    // 增加库存
                    Integer stock = wareSkuEntity.getStock() + item.getStock();
                    boolean updated = wareSkuService.lambdaUpdate()
                            .set(WareSkuEntity::getStock, stock)
                            .set(WareSkuEntity::getVersion, version)
                            .eq(WareSkuEntity::getSkuId, item.getSkuId())
                            .eq(WareSkuEntity::getVersion, wareSkuEntity.getVersion())
                            .update();
                    if (!updated) throw new RuntimeException("库存信息更新失败");
                }
            });
        } catch (IOException e) {
            throw new RuntimeException("获取商品信息失败-Jason");
        }


        boolean updatedBatchPurchaseDetailById = purchaseDetailService.updateBatchById(purchaseDetailEntities);
        if (!updatedBatchPurchaseDetailById)
            throw new RuntimeException("领取失败");

        boolean updatedBatchById = this.updateById(purchaseEntity);
        if (!updatedBatchById)
            throw new RuntimeException("领取失败");
    }

}